package com.moorror.codegenvel.view.component;

import com.google.common.collect.Maps;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentFactory;
import com.intellij.ui.content.ContentManagerEvent;
import com.intellij.ui.content.ContentManagerListener;
import org.jetbrains.annotations.NotNull;

import java.util.Map;

/**
 * @Author jiyanghuang
 * @Date 2022/8/7 13:50
 */
public class CodeGenByVelocityComponent implements ContentManagerListener {

    private static final Logger LOGGER = Logger.getInstance(CodeGenByVelocityComponent.class);

    private Project project;

    /**
     * {"currentContentTabName": "AbstractToolSetTab"}
     */
    private Map<String, AbstractCodeGenByVelocitySetTab> toolSetTabMap = Maps.newHashMap();

    /**
     * {"displayName-tabId":{"className":object}}
     */
    private Map<String, Map<String, Object>> objectCacheMap = Maps.newConcurrentMap();

    /**
     * 当前窗口
     */
    private ToolWindow toolWindow;

    /**
     * 生成对象
     *
     * @param project
     */
    protected CodeGenByVelocityComponent(Project project) {
        this.project = project;
    }

    /**
     * 类似于 spring 获取 bean 对象
     *
     * @param project
     * @return
     */
    public static CodeGenByVelocityComponent getInstance(Project project) {
        return project.getService(CodeGenByVelocityComponent.class);
//        return ComponentManager.getService(CodeGenByVelocityComponent.class):
//        return ServiceManager.getService(project, CodeGenByVelocityComponent.class);
    }

    /**
     * 初始化组件
     */
    public void initRestComponent(ToolWindow toolWindow) {

        // 添加内容变更监听器
        toolWindow.getContentManager().addContentManagerListener(this);

        Content content;
        ContentFactory contentFactory = ApplicationManager.getApplication().getService(ContentFactory.class);

        CodeGenDataTab codeGenDataTab = new CodeGenDataTab(project);
        content = contentFactory.createContent(codeGenDataTab.panelShow(), codeGenDataTab.tabName(), false);
        toolWindow.getContentManager().addContent(content);
        toolSetTabMap.put(codeGenDataTab.tabName(), codeGenDataTab);

        CodeGenXRenderDataTab codeGenXRenderDataTab = new CodeGenXRenderDataTab(project);
        content = contentFactory.createContent(codeGenXRenderDataTab.panelShow(), codeGenXRenderDataTab.tabName(), false);
        toolWindow.getContentManager().addContent(content);
        toolSetTabMap.put(codeGenXRenderDataTab.tabName(), codeGenXRenderDataTab);

        JsonTab jsonTab = new JsonTab(project);
        content = contentFactory.createContent(jsonTab.panelShow(), jsonTab.tabName(), false);
        toolWindow.getContentManager().addContent(content);
        toolSetTabMap.put(jsonTab.tabName(), jsonTab);

        toolWindow.activate(new Thread(), true);


    }


    /**
     * 创建面板界面
     */
    public <T extends AbstractCodeGenByVelocitySetTab> Content createRestClientContentPanel(Class<T> tabClass, Project project) {
        try {
            AbstractCodeGenByVelocitySetTab toolSetTab = tabClass.getDeclaredConstructor().newInstance();
            toolSetTab.setProject(project);
            Content content = ApplicationManager.getApplication().getService(ContentFactory.class).createContent(toolSetTab.panelShow(), toolSetTab.tabName(), false);
            content.setCloseable(false);
            return content;
        } catch (Exception ex) {
            LOGGER.error(String.format("createRestClientContentPanel"), ex);
            return null;
        }
    }

    @Override
    public void selectionChanged(@NotNull ContentManagerEvent event) {

    }


    public void register(Class<?> clazz, Object impl) {

    }

    /**
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> T findInstance(Class<T> clazz) {
        if(null == toolWindow){
            return null;
        }
        String displayName = toolWindow.getContentManager().getSelectedContent().getDisplayName();
        String tabId = toolSetTabMap.get(displayName).getToolSetTabBar().getSelectedInfo().getText();
        Map<String, Object> classNameMap = objectCacheMap.get(cacheObjectKey(displayName, tabId));
        if (null != classNameMap) {
            T t = (T) classNameMap.get(clazz.getName());
            if (null == t) {
                LOGGER.error(String.format("findInstance Object not init"));
                return null;
            }
            return t;
        }
        return null;
    }

    /**
     *
     * @param clazz
     * @param displayName
     * @param <T>
     * @return
     */
    public <T> T findInstance(Class<T> clazz, String displayName) {
        AbstractCodeGenByVelocitySetTab abstractSequenceOutLineSetTab = toolSetTabMap.get(displayName);
        if (null == abstractSequenceOutLineSetTab) {
            return null;
        }
        String tabId = abstractSequenceOutLineSetTab.getToolSetTabBar().getSelectedInfo().getText();
        Map<String, Object> classNameMap = objectCacheMap.get(cacheObjectKey(displayName, tabId));
        if (null == classNameMap) {
            return null;
        }
        T t = (T) classNameMap.get(clazz.getName());
        return t;
    }

    /**
     * @param clazz
     * @param displayName
     * @param <T>
     * @return
     */
    public <T> T findInstanceLeft(String displayName) {
        AbstractCodeGenByVelocitySetTab abstractSequenceOutLineSetTab = toolSetTabMap.get(displayName);
        if (null == abstractSequenceOutLineSetTab) {
            return null;
        }
        String tabId = abstractSequenceOutLineSetTab.getToolSetTabBar().getSelectedInfo().getText();
        Map<String, Object> classNameMap = objectCacheMap.get(cacheObjectKey(displayName, tabId));
        if (null == classNameMap) {
            return null;
        }
        TabContentRightShow t = (TabContentRightShow) classNameMap.get(TabContentRightShow.class.getName());
        return (T) t.getT();
    }

    /**
     *
     * @param clazz
     * @param displayName
     * @param tabId
     * @param <T>
     * @return
     */
    public <T> T findInstance(Class<T> clazz, String displayName, String tabId) {
        Map<String, Object> classNameMap = objectCacheMap.get(cacheObjectKey(displayName, tabId));
        if (null == classNameMap) {
            return null;
        }
        T t = (T) classNameMap.get(clazz.getName());
        return t;
    }

    public void register(AbstractCodeGenByVelocitySetTab abstractToolSetTab, String tabId, Class<?> clazz, Object impl) {
        String displayNameTabIdKey = cacheObjectKey(abstractToolSetTab.tabName(), tabId);
        Map<String, Object> classNameMap = objectCacheMap.get(displayNameTabIdKey);
        if (null == classNameMap) {
            classNameMap = Maps.newConcurrentMap();
            objectCacheMap.put(displayNameTabIdKey, classNameMap);
        }
        classNameMap.put(clazz.getName(), impl);
    }


    public void addTab(AbstractCodeGenByVelocitySetTab tab){
        toolSetTabMap.put(tab.tabName(), tab);
    }

    public void removeRegister(String tabId) {
        String displayName = toolWindow.getContentManager().getSelectedContent().getDisplayName();
        objectCacheMap.remove(cacheObjectKey(displayName, tabId));
    }

    public String cacheObjectKey(String displayName, String tabId) {
        return displayName + "-" + tabId;
    }

    public ToolWindow getToolWindow() {
        return toolWindow;
    }

    public void setToolWindow(ToolWindow toolWindow) {
        this.toolWindow = toolWindow;
    }

    public String displayName() {
        return toolWindow.getContentManager().getSelectedContent().getDisplayName();
    }

    public boolean selectTab(String displayName) {
        if (null == toolWindow) {
            return false;
        }
        if (!toolWindow.isActive()) {
            toolWindow.activate(() -> {
                Content contentFind = toolWindow.getContentManager().findContent(displayName);
                toolWindow.getContentManager().setSelectedContent(contentFind, true);
            });
            return true;
        }
        Content contentFind = toolWindow.getContentManager().findContent(displayName);
        toolWindow.getContentManager().setSelectedContent(contentFind, true);
        return true;
    }
}
